﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Wisdom.Core
{
    public abstract class TasksRegistry : ITasksRegistry
    {
        protected readonly IList<TaskConfiguration> tasks = new List<TaskConfiguration>();

        /// <summary>
        /// Gets or sets the tasks.
        /// </summary>
        /// <value>The tasks.</value>
        public virtual IEnumerable<KeyValuePair<Type, Action<object>>> TaskConfigurations
        {
            get
            {
                return tasks.Select(configuration => new KeyValuePair<Type, Action<object>>(configuration.TaskType, configuration.Configure));
            }
        }

        protected void Include(Type taskType, Action<object> configure)
        {
            IEnumerable<Type> requires = taskType.GetCustomAttributes(typeof(DependsOnAttribute), true)
                                             .Cast<DependsOnAttribute>()
                                             .Select(a => a.TaskType)
                                             .Distinct()
                                             .ToList();

            foreach (Type require in requires)
            {
                Include(require, null);
            }

            if (tasks.All(c => c.TaskType != taskType))
            {
                tasks.Add(new TaskConfiguration { TaskType = taskType, Configure = configure });
            }
        }

        /// <summary>
        /// Excludes this instance.
        /// </summary>
        /// <returns></returns>
        protected virtual void Exclude(Type taskType)
        {
            IEnumerable<TaskConfiguration> taskConfigurations = tasks.Where(c => c.TaskType == taskType).ToList();

            foreach (TaskConfiguration taskConfiguration in taskConfigurations)
            {
                tasks.Remove(taskConfiguration);
            }
        }

        protected sealed class TaskConfiguration
        {
            public Type TaskType { get; set; }

            public Action<object> Configure { get; set; }
        }
    }
}